﻿using HDS.Common.Helper;
using HDS.Data;
using HDS.IService.Sys;
using HDS.Model;
using HDS.Model.Entity.Sys;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace HDS.Service.Sys
{
    public class SysUserService : ISysUserService
    {
        private SysDbContext db = new SysDbContext();

        public async Task<SysUser> Get(int userId)
        {
            return await db.SysUser.GetByIdAsync(userId);
        }

        public async Task<SysUser> Get(int userId, string userPwd)
        {
            return await db.SysUser.GetSingleAsync(e => e.UserId.Equals(userId) && e.UserPwd.Equals(userPwd.CreatePassword()));
        }

        public async Task<SysUser> Get(string userEmail, string userPwd)
        {
            return await db.SysUser.GetSingleAsync(e => e.UserEmail.Equals(userEmail) && e.UserPwd.Equals(userPwd.CreatePassword()));
        }

        public async Task<DataPagingModel<SysUser>> GetList(Expression<Func<SysUser, bool>> whereExpression, int pageIndex = 1, int pageSize = 20)
        {
            RefAsync<int> total = 0;
            var rows = await db.Db.Queryable<SysUser>().WhereIF(whereExpression != null, whereExpression).OrderBy(e => e.UserStatus, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize, total);
            return new DataPagingModel<SysUser>
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                PageTotal = (total.Value + pageSize - 1) / pageSize,
                Total = total.Value,
                Rows = rows
            };
        }

        public async Task<ResultData<SysUser>> Register(SysUser user)
        {
            var old = await db.SysUser.GetSingleAsync(e => e.UserEmail.Equals(user.UserEmail));
            if (old != null)
                return new ResultData<SysUser> { Success = false, Code = ErrorCode.DataValidationFailed, Message = "emailAlreadyExists", Data = null };

            user.UserPwd = user.UserPwd.CreatePassword();

            var userId = await db.SysUser.InsertReturnIdentityAsync(user);
            if (userId > 0)
            {
                user.UserId = userId;
                return new ResultData<SysUser> { Success = true, Data = user };
            }
            else
            {
                return new ResultData<SysUser> { Success = false, Code = ErrorCode.SystemError, Message = "", Data = null };
            }
        }

        public async Task Update(SysUser user)
        {
            await db.SysUser.UpdateAsync(u => new SysUser { UserName = user.UserName, UserPhone = user.UserPhone, UserStatus = user.UserStatus }, e => e.UserId == user.UserId);
        }

        public async Task UpdatePwd(int userId, string userPwd)
        {
            await db.SysUser.UpdateAsync(u => new SysUser { UserPwd = userPwd.CreatePassword() }, e => e.UserId == userId);
        }

        public async Task Disable(int userId)
        {
            await db.SysUser.UpdateAsync(u => new SysUser { UserStatus = false }, e => e.UserId == userId);
        }

        public async Task Enable(int userId)
        {
            await db.SysUser.UpdateAsync(u => new SysUser { UserStatus = true }, e => e.UserId == userId);
        }


        public async Task<List<SysRole>> GetRoles(int userId)
        {
            return await db.Db.Queryable<SysUserRole, SysRole>((ur, r) => new JoinQueryInfos(
                 JoinType.Inner, ur.RoleId == r.RoleId
            )).Where(ur => ur.UserId == userId).Select<SysRole>().ToListAsync();
        }

        public async Task SetRoles(int userId, int[] roleIds)
        {
            await db.SysUserRole.DeleteAsync(e => e.UserId == userId);

            if (roleIds.Any())
            {
                var userRoles = roleIds.Select(e => new SysUserRole { Id = 0, RoleId = e, UserId = userId }).ToArray();
                await db.SysUserRole.InsertRangeAsync(userRoles);
            }
        }

        public async Task<List<SysFun>> GetFuns(int userId)
        {
            return await db.Db.Queryable<SysUserRole, SysRoleFun, SysFun>((ur, rf, f) => new JoinQueryInfos(
                 JoinType.Inner, ur.RoleId == rf.RoleId,
                 JoinType.Inner, rf.FunId == f.FunId
            )).Where(ur => ur.UserId == userId).Select<SysFun>().Distinct().ToListAsync();
        }

        public async Task<bool> HasFun(int userId, string url)
        {
            var user = await db.SysUser.GetSingleAsync(e => e.UserId.Equals(userId));
            if (user == null || !user.UserStatus)
                return false;

            var fun = await db.SysFun.GetSingleAsync(e => e.FunUrl.Equals(url));
            if (fun == null)
                return true;

            return await db.Db.Queryable<SysUserRole, SysRoleFun>((ur, rf) => new JoinQueryInfos(
                 JoinType.Inner, ur.RoleId == rf.RoleId
            )).Where((ur,rf) => ur.UserId == userId && rf.FunId == fun.FunId).AnyAsync();
        }
    }
}